<template>
  <div id="codeContainer" class="code-editor">
    <codemirror
      ref="cmRef"
      v-model="code"
      :options="cmOptions"
      :style="{ height: `${height}px`, width: '100%' }"
    />
  </div>
</template>

<script lang="ts">
import {
  Vue,
  Component,
  Prop,
  PropSync,
  Watch,
  Ref,
} from 'vue-property-decorator'
// @ts-ignore
import { codemirror } from 'vue-codemirror'
import 'codemirror/lib/codemirror.css'
// import 'codemirror/mode/sql/sql' //  mode: 'text/x-sql'
import './sql/sql-extend'
// 加提示的引用
import 'codemirror/addon/hint/show-hint'
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/sql-hint'
// Sublime Text风格的键盘映射
import 'codemirror/keymap/sublime'
// 选中词高亮
import 'codemirror/addon/search/match-highlighter'

@Component({
  name: 'CodeEditor',
  components: {
    codemirror,
  },
})
export default class CodeEditor extends Vue {
  @Ref('cmRef') readonly cmRef: any
  /** code */
  @PropSync('value', { type: String }) code!: boolean
  /** 编辑器模式 */
  @Prop({ type: String, default: 'text/x-sql' }) mode!: string
  /** 编辑器高 */
  @Prop({ type: String, default: 'auto' }) height!: string
  /** 默认文本 */
  @Prop({ type: String, default: 'Code goes here...' }) placeholder!: string
  /** 是否显示行号 */
  @Prop({ type: Boolean, default: true }) lineNumber!: boolean
  /** 是否提示lint 信息 */
  @Prop({ type: Boolean, default: true }) lintMarker!: boolean
  /** TAB SIZE */
  @Prop({ type: Number, default: 2 }) tabSize?: number = 2
  /** readOnly */
  @Prop({ type: Boolean, default: false }) readOnly!: boolean
  /** 自动聚焦 */
  @Prop({ type: Boolean, default: true }) autofocus!: boolean

  // CM 常规配置项
  public cmOptions: any = {
    tabSize: this.tabSize,
    mode: this.mode,
    lineNumbers: this.lineNumber, // 行号
    lineWrapping: true,
    // line: true,
    selectionPointer: 'pointer',
    lint: this.lintMarker,
    matchBrackets: true,
    autofocus: this.autofocus,
    readOnly: this.readOnly,
    styleActiveLine: true,
    highlightSelectionMatches: { showToken: /\w/, annotateScrollbar: true },
    placeholder: 'Code goes here...',
    hintOptions: {
      completeSingle: false,
      // 自定义的提示选项
      // tables: {
      //   users: [ 'name', 'score' ],
      //   countries: ['name', 'pop']
      // },
      // name: {
      //
      // }
    },
    keyMap: 'sublime',
    autoCloseBrackets: true,
  }

  private currentSelection: string = ''

  /**
   * 添加提示
   * @private
   */
  private addHint() {
    // 加提示
    this.cmRef.codemirror.on('inputRead', (cm: any) => {
      cm.showHint()
    })
    // 获取选中的内容
    this.cmRef.codemirror.on('cursorActivity', (cm: any) => {
      this.currentSelection = cm.getSelection()
    })
  }

  /**
   * 高亮代码
   * @private
   */
  public setCodeHighlight(highlightList: any[]) {
    highlightList?.forEach(({ from }: any) => {
      // this.cmRef.codemirror.markText(from, to, options)
      this.cmRef.codemirror.addLineClass(
        from.line,
        'background',
        'cm-custom-line-error-highlight'
      )
    })
  }

  /**
   * 清除高亮代码
   * @private
   */
  private clearCodeHighlight() {
    this.cmRef.codemirror.eachLine((line: any) => {
      this.cmRef.codemirror.removeLineClass(
        line,
        'background',
        'cm-custom-line-error-highlight'
      )
    })
  }

  /**
   *  高度的变动
   */
  @Watch('height')
  private getHeightValue(newValue: string) {
    this.setCodeMirrorHeight(newValue)
  }

  /**
   * 设置 codemirror 高度
   * @param height
   * @private
   */
  private setCodeMirrorHeight(height: number | string) {
    this.$nextTick(() => {
      const cmElement = document.querySelector(
        '#codeContainer .CodeMirror'
      ) as HTMLTextAreaElement
      cmElement.style.height = `${height}px`
      cmElement.style.maxHeight = `${height}px`
    })
  }

  private created() {}

  private mounted() {
    // 初始化 codeMirror 高度
    this.addHint()
    if (this.height !== 'auto') {
      //  传参有height， 渲染之后设置
      this.setCodeMirrorHeight(this.height)
    }
  }
}
</script>

<style lang="less" scoped>
.code-editor {
  height: 100%;
  width: 100%;
}

:deep(.CodeMirror) {
  font-family: 'Courier New', Consolas, Menlo, Monaco, serif;
  font-size: 16px;
  font-weight: 500;
  height: auto;
  line-height: 20px;

  .CodeMirror-placeholder {
    color: #999;
  }

  // 自定义错误高亮
  .cm-custom-error-highlight {
    background-color: #f1c40f;
  }

  .cm-custom-line-error-highlight {
    background-color: #ffe5e7;
  }
}

// 整词匹配 (匹配选中的整词) highlight
:deep(.CodeMirror-focused .cm-matchhighlight) {
  background-color: rgba(149, 177, 241, 0.3);
}

:deep(.CodeMirror-vscrollbar) {
  &::-webkit-scrollbar {
    width: 6px;
  }

  &::-webkit-scrollbar-thumb {
    background: rgba(144, 147, 153, 0.5);
    border-radius: 6px;
  }

  &::-webkit-scrollbar-track {
    background: transparent;
    border-radius: 5px;
  }
}
</style>
